<template>
  <div class="container">
    <div class="init-ui" v-if="startChat === false">
      <div class="intelligent-logo">
        <img src="../assets/icon/logo.png" alt="" class="logo"/>
        <div class="logo-text">智能求医</div>
      </div>

      <div class="blank"></div>

      <div class="ask-area">
        <div class="carousel-text"></div>
        <div>
          <el-input
              class="textarea"
              type="textarea"
              :rows="6"
              resize="none"
              placeholder="尽管问..."
              v-model="userQuestion"
              @keyup.enter.native="startChatWithGpt"
          >
          </el-input>
        </div>
        <el-button icon="el-icon-s-promotion" type="primary" size="small" class="submit-btn" @click="startChatWithGpt">
          发送
        </el-button>
      </div>

      <div class="tip-area">
        <div class="top-tips">
          <div class="tip-item" @click="askGptWithDefault('青光眼的眼底有什么特征？')">🤔青光眼的眼底有什么特征？</div>
          <div class="tip-item" style="margin-left: 20px;" @click="askGptWithDefault('️‍我该怎么预防眼底疾病？')">👁️‍🗨️我该怎么预防眼底疾病？</div>
        </div>
        <div class="bottom-tips">
          <div class="tip-item" @click="askGptWithDefault('通过眼底诊断出糖尿病后该如何治疗？')">💦通过眼底诊断出糖尿病后该如何治疗？</div>
          <div class="tip-item" style="margin-left: 20px;" @click="askGptWithDefault('专栏：11种眼底疾病，你都了解吗？')">👀专栏：11种眼底疾病，你都了解吗？</div>
          <div class="tip-item" style="margin-left: 20px;" @click="askGptWithDefault('新闻：我国眼底病患者总数超4000万。')">🚨新闻：我国眼底病患者总数超4000万。</div>
        </div>
      </div>
    </div>
    <div class="start-ui" v-else>
      <el-card class="chat-card">
        <div class="chat-area">
          <div class="single-chat" v-for="(item,index) in chatHistory" :key="index">
            <div class="model-answer" v-if="item.role === 0">
              <img class="model-avatar" src="https://service-plat.oss-cn-beijing.aliyuncs.com/model_avatar.png" alt=""/>
              <div class="markdown-body" v-html="item.content"></div>
            </div>
            <div class="user-ask" v-else>
              <div class="user-ask-inner">
                <div class="user-content">{{ item.content }}</div>
                <el-avatar class="user-avatar"
                           src="https://service-plat.oss-cn-beijing.aliyuncs.com/avatar.jpg"></el-avatar>
              </div>
            </div>
          </div>
        </div>

        <div class="more-ask-area">
          <el-input
              type="textarea"
              :rows="6"
              resize="none"
              placeholder="还有什么问题？尽管问!"
              v-model="userQuestion"
              @keyup.enter.native="startChatWithGpt"
          >
          </el-input>
          <el-button icon="el-icon-s-promotion" type="primary" size="small" class="more-submit-btn"
                     @click="startChatWithGpt">
            发送
          </el-button>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script>
import {io} from "socket.io-client";
import hljs from "highlight.js";

export default {
  name: 'IntelligentMedical',
  data() {
    return {
      tmpAnswer: '',
      nowHTML: '',
      // 是否开启了对话 用来控制当前展示哪个页面
      startChat: false,
      talkTitle: [
        '洞察眼底，我是你的健康专家',
        '智能识别，我是你的贴心伙伴',
        '一查即准，我是你的诊断先锋',
        '一问即答，我是你的健康顾问',
        '有症必查，我是你的智能卫士',
        '有影必析，我是你的分析能手'
      ],
      // 循环打字的定时器id
      sayWordId: undefined,
      // 用户输入的问题
      userQuestion: '',
      // 聊天记录 role==0代表大模型 1代表用户
      chatHistory: [],
      // socketio
      socket: null,
      // 如果用户使用了默认的内容 就会改变这个值为默认内容
      defaultQuestion: undefined
    }
  },
  mounted() {
    this.sayWord()
    this.initSocket();
  },
  beforeDestroy() {
    // 离开时断开Socketio连接
    if (this.socket !== null) {
      this.socket.disconnect();
    }
  },
  methods: {
    initSocket() {
      this.socket = io('https://yiyuy.mynatapp.cc/spark', {
        transports:['websocket']
      })

      this.socket.on('disconnect', (msg) => {
        this.socket.disconnect()
      })

      // 监听服务器那边返回的消息
      this.socket.on('server_response', (message) => {
        // 收到服务器推送的消息，可以跟进自身业务进行操作
        if (message.data === '[over]') {

        } else {
          this.tmpAnswer += message.data;
          this.mdToHtml(this.tmpAnswer, (html) => {
            this.nowHTML = html;
          })
        }
      })
    },
    sayWord() {
      const text = document.querySelector('.carousel-text');
      const txt = this.talkTitle

      var index = 0;
      var xiaBiao = 0;
      var huan = true;

      this.sayWordId = setInterval(function () {

        if (huan) {
          if (index >= 9) {
            text.innerHTML = txt[xiaBiao].slice(0, 9) + '<font color="#6495ed">' + txt[xiaBiao].slice(9, ++index) + '</font>';
          } else {
            text.innerHTML = txt[xiaBiao].slice(0, ++index);
          }
        } else {
          if (index >= 9) {
            text.innerHTML = txt[xiaBiao].slice(0, 9) + '<font color="#6495ed">' + txt[xiaBiao].slice(9, index--) + '</font>';
          } else {
            text.innerHTML = txt[xiaBiao].slice(0, index--);
          }
        }

        if (index == txt[xiaBiao].length + 3) {
          huan = false;
        } else if (index < 0) {
          index = 0;
          huan = true;
          xiaBiao++;
          if (xiaBiao >= txt.length) {
            xiaBiao = 0;
          }
        }

      }, 180)
    },
    // 使用下方自带的内容询问大模型
    askGptWithDefault(content) {
      this.defaultQuestion = content
      this.startChatWithGpt();
    },
    startChatWithGpt() {
      // 如果用户输入内容为空
      let question = '';
      if (this.userQuestion.length <= 0) {
        // 但是使用了默认内容
        if ( this.defaultQuestion !== undefined ) {
          question = this.defaultQuestion
          this.defaultQuestion = undefined
        }else {
          this.$message.warning('请先输入内容')
          return;
        }
      }else {
        question = this.userQuestion
        this.userQuestion = ''
      }

      this.startChat = true

      // 关闭循环打字机
      if (this.sayWordId !== undefined) {
        clearInterval(this.sayWordId)
      }

      // 把用户问题加入历史记录 同时清空大模型回答内容
      this.chatHistory.push({
        role: 1,
        content: question
      })

      // 加入一条大模型的回答内容 开始构造流式回答
      // answer代表chatHistory中的值 是经过markdown处理后的
      // tmpAnswer 只是一个临时的值 用来拼接完整的大模型回复
      let answer = ''
      this.tmpAnswer = ''
      this.nowHTML = ''
      this.chatHistory.push({
        role: 0,
        content: ''
      })

      // 做到打字机效果
      let that = this
      setInterval(function () {
        let len = that.chatHistory.length;
        if (that.nowHTML.length > answer.length) {
          let nowLen = answer.length;
          if (that.nowHTML[nowLen] === '<') {
            while (that.nowHTML[nowLen] !== '>') {
              nowLen++;
            }
          }
          answer = that.nowHTML.slice(0, nowLen + 1);
          that.chatHistory[len - 1].content = answer;
        }
      }, 40)

      this.socket.emit('startTalk',{question: question})
    },
    // 将md转化为html
    mdToHtml(content, callback) {
      import('markdown-it').then(module => {
        const md = module.default('commonmark', {
          highlight: function (str, lang) {
            if (lang && hljs.getLanguage(lang)) {
              try {
                return '<pre class="hljs"><code>' +
                    hljs.highlight(lang, str, true).value +
                    '</code></pre>';
              } catch (__) {
              }
            }

            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
          }
        });
        callback(md.render(content));
      });
    }
  }
}
</script>

<style lang="less" scoped>
@keyframes MoveIn {
  0% {
    opacity: 0;
    transform: translateY(12px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.container {
  width: 100%;
  height: 100%;
  background-color: #f3f5fa;
  padding: 0;

  .init-ui {
    width: 100%;
    height: 100%;
    animation: MoveIn .7s cubic-bezier(.4, 0, .2, 1);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    .intelligent-logo {
      display: flex;
      align-items: center;

      .logo {
        width: 100px;
        height: 100px;
      }

      .logo-text {
        display: flex;
        align-items: center;
        text-align: center;
        font-size: 40px;
        font-weight: 600;
        color: #333;
        font-family: "FZYaoti", cursive, serif, sans-serif;
        letter-spacing: 20px
      }
    }

    .blank {
      width: 100%;
      height: 5%;
    }

    .ask-area {
      width: 70%;
      position: relative;
      display: flex;
      flex-direction: column;

      .carousel-text {
        height: 40px;
        font-size: 25px;
        font-weight: bold;
      }

      .textarea {
        font-size: 17px;
        flex: 1;
        width: 100%;
        z-index: 10;
        box-sizing: border-box;
        position: relative;
        border: 1px solid #e5e5e5;
        border-radius: 16px;
        transition: box-shadow .3s cubic-bezier(.36, .66, .04, 1);
        box-shadow: none;
        background-color: #fff;
      }

      .submit-btn {
        position: absolute;
        bottom: 10px;
        right: 10px;
        z-index: 11
      }
    }

    .tip-area {
      margin-top: 20px;

      .top-tips {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .bottom-tips {
        width: 100%;
        margin-top: 10px;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .tip-item {
        padding: 7px 12px 7px 8px;
        border-radius: 12px;
        height: 44px;
        max-width: 100%;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
        box-sizing: border-box;
        font-family: PingFang SC, sans-serif;
        font-size: 14px;
        cursor: pointer;
        background-color: #ffffff;
        transition: background-color .3s cubic-bezier(.36, .66, .04, 1);
        border: 1px solid #e5e5e5;
        color: rgba(0, 0, 0, .87);
        text-decoration: none;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: bold;
      }

      .tip-item:hover {
        background-color: #e5e5e5;
      }
    }
  }

  .start-ui {
    height: 100%;
    width: 100%;
    padding: 0;

    .chat-card {
      margin: 20px auto;
      height: 90%;
      width: 90%;
      border-radius: 10px;
      border: 1px solid #e5e5e5;
      padding: 5px;
      display: flex;
      flex-direction: column;


      /deep/ .el-card__body {
        height: 100%;
      }

      .chat-area {
        width: 100%;
        height: 82.5%;
        overflow-y: auto;

        .single-chat {
          width: 100%;
          animation: MoveIn .3s cubic-bezier(.4, 0, .2, 1) forwards;
          margin-top: 15px;

          .model-answer {
            display: flex;
            align-items: center;
            height: 100%;

            .markdown-body {
              color: #24292f;
              font-size: 14px;
              word-wrap: break-word;
              padding-left: 10px;
              padding-right: 10px;
              border-radius: 10px;
              background-color: #f5f7fa;
              border: 1px solid #e5e5e5;
              margin-left: 10px;
            }

            .model-avatar {
              width: 40px;
              height: 40px;
            }
          }

          .user-ask {
            width: 100%;
            align-items: center;
            display: flex;
            justify-content: flex-end;

            .user-ask-inner {
              display: flex;
              align-items: center;

              .user-content {
                padding: 10px;
                border-radius: 10px;
                background-color: #2d65f7;
                color: #ffffff;
              }

              .user-avatar {
                margin-left: 10px;
              }
            }
          }
        }
      }

      .more-ask-area {
        flex: 1;
        border: 1.5px solid #e5e5e5;
        border-radius: 5px;
        position: relative;

        .more-submit-btn {
          position: absolute;
          right: 10px;
          bottom: 10px;
        }
      }
    }
  }
}

</style>